package com.example.student_manager_backend.aspect;

import com.example.student_manager_backend.entity.OperationLog;
import com.example.student_manager_backend.service.OperationLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;

/**
 * 日志切面类
 * 用于自动记录系统中的操作日志，包括请求参数、响应结果、执行时间等
 */
@Aspect
@Component
public class LoggingAspect {
    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

    @Autowired
    private OperationLogService operationLogService;

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 定义切点
     * 拦截所有Controller层的方法
     */
    @Pointcut("execution(* com.example.student_manager_backend.controller.*.*(..))")
    public void controllerPointcut() {}

    /**
     * 环绕通知
     * 记录方法执行前后的日志信息
     *
     * @param joinPoint 连接点
     * @return 方法执行结果
     * @throws Throwable 可能抛出的异常
     */
    @Around("controllerPointcut()")
    public Object logControllerMethods(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = null;
        OperationLog log = new OperationLog();
        
        try {
            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                log.setIpAddress(getClientIp(request));
                log.setOperator(request.getHeader("X-User-Name")); // 从请求头获取操作人
            }

            // 设置基本信息
            log.setOperationType(joinPoint.getSignature().getName());
            log.setOperationContent(joinPoint.getTarget().getClass().getSimpleName());
            log.setOperationTime(new Date());
            log.setRequestParams(objectMapper.writeValueAsString(joinPoint.getArgs()));

            // 执行目标方法
            result = joinPoint.proceed();

            // 设置响应结果
            log.setResponseResult(objectMapper.writeValueAsString(result));
            log.setStatus("SUCCESS");
        } catch (Exception e) {
            log.setStatus("FAILED");
            log.setErrorMessage(e.getMessage());
            throw e;
        } finally {
            // 计算执行时间
            long endTime = System.currentTimeMillis();
            log.setExecutionTime(endTime - startTime);
            
            // 保存日志
            operationLogService.saveLog(log);
            
            // 打印日志
            logger.info("Method: {}, Execution Time: {}ms, Status: {}", 
                log.getOperationType(), 
                log.getExecutionTime(), 
                log.getStatus());
        }
        
        return result;
    }

    /**
     * 获取客户端IP地址
     *
     * @param request HTTP请求
     * @return IP地址
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
} 